#ifndef PROCESSPOOL_HPP
#define PROCESSPOOL_HPP

#include <iostream>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <functional>

#include "Channel.hpp"
#include "Task.hpp"
typedef std::function<void()> Work_t; // 回调函数
enum
{
    OK = 0,
    UsageError,
    PipeError,
    ForkError
};

class ProcessPool
{

public:
    ProcessPool(int n, Work_t work) : _processNum(n), _work(work) {}
    ProcessPool(int n) : _processNum(n) {}

    // 初始化进程池
    int InitProcessPool()
    {
        // 1. 创建指定个数个进程
        for (int i = 0; i < _processNum; i++)
        {
            // 1. 先要有管道
            int pipefd[2];
            if (pipe(pipefd) < 0)
                return PipeError;
            // 2. 创建子进程
            pid_t pid = fork();
            if (pid < 0)
                return ForkError;
            // 3. 建立通信管道
            if (pid == 0)
            {
                // 子进程
                //  关闭历史wfd
                std::cout << getpid() << " child close history fd: ";
                for (auto x : _channels)
                {
                    //     std::cout<<x.getWfd()<<' ';
                    x.close();
                }
                std::cout << std::endl;
                //  std::cout<<"debug"<<' '<<pipefd[1]<<std::endl;
                close(pipefd[1]); // 关闭当前写端
                // 修改读端为标准输入
                dup2(pipefd[0], 0);
                _work(); // 执行原始动作
                exit(0);
            }
            else
            {
                // 父进程
                close(pipefd[0]);                             // 关闭当前读端
                _channels.push_back(Channel(pipefd[1], pid)); // 保存管道
            }
        }
        return OK;
    }
    void DispathTask(unsigned long nums)
    {
        // 这里采用轮询遍历法
        int ir = 0;

        // 2.分发任务
        while (nums--)
        {

            // int taskid=0;
            // //  std::cin>>taskid;
            // std::cout<<"收到任务："<<taskid<<std::endl;
            // if(taskid>=taskPool.GetTaskNum() || taskid<0)
            // {
            //     std::cout<<taskPool.GetTaskNum()<<std::endl;
            //     // 任务池中没有该任务，跳过
            //     std::cout<<"任务池中没有该任务，跳过"<<std::endl;
            //     nums++;
            //     continue;
            // }
            // a.选择一个任务，整数
            int taskid = taskPool.SelectTasks();
            // b.选择一个子进程channel
            Channel &curr = _channels[ir++];

            // 打印消息
            std::cout << "#############################################\n";
            std::cout << getpid() << " dispatch task " << taskid << " to " << curr.getName() << std::endl;
            std::cout << "任务还剩：" << nums << std::endl;
            std::cout << "#############################################\n";

            // c.发送任务
            curr.Send(taskid);

            sleep(1);
        }
    }
    // 进程池的回收
    void QuitProcessPool()
    {

        // Version 3:
        for ( auto x : _channels)
        {
            x.close();  // 关闭所有管道的写端
            pid_t rid = waitpid(x.getWho(), NULL, 0);   // 等待所有子进程结束，回收子进程
            if (rid > 0)
            {
                std::cout << "child" << rid << "wait... success" << std::endl;
            }
        }

        // Version 2:   关闭所有管道的写端的同时，等待子进程结束，回收子进程
        //  for(auto x:_channels)
        // 这里需要注意如果我们建立子进程的时候，没有关闭之前的历史wfd，那么这里会导致前面管道的wfd被后面多个子进程继承，此时必须从后往前关闭wfd
        // for(int i=_channels.size()-1;i>=0;i--)
        // {
        //     _channels[i].close();  // 关闭所有管道的写端
        //     pid_t rid=waitpid(_channels[i].getWho(),NULL,0);   // 等待所有子进程结束，回收子进程
        //     if(rid>0)
        //     {
        //         std::cout<<"child"<<rid<<"wait... success"<<std::endl;
        //     }
        // }

        // Version 1: 等待所有子进程结束，回收子进程
        //  for(auto x:_channels)
        //  {
        //      x.close();  // 关闭所有管道的写端
        //  }
        //  for(auto x:_channels)
        //  {
        //      pid_t rid=waitpid(x.getWho(),NULL,0);   // 等待所有子进程结束，回收子进程
        //      if(rid>0)
        //      {
        //          std::cout<<"child"<<rid<<"wait... success"<<std::endl;
        //      }
        //  }
    }

private:
    std::vector<Channel> _channels;
    int _processNum;       // 进程数
    Work_t _work = Worker; // 执行的任务函数
};

#endif // PROCESSPOOL_HPP
